//
// Created by jinyf on 2022/3/2.
//


#include "MNFFmpeg.h"


//这个是C函数，C函数是访问不到任何C++的环境变量的
//所以要转换，通过小技巧
void *decodeFFmpeg(void *data) {
    MNFFmpeg *wlffmpeg = static_cast<MNFFmpeg *>(data);
    wlffmpeg->decodeFFmpegThread();
    pthread_exit(&wlffmpeg->decodeThread);
}


MNFFmpeg::~MNFFmpeg() {
    pthread_mutex_destroy(&seek_mutex);
    pthread_mutex_destroy(&init_mute);
}

MNFFmpeg::MNFFmpeg(MNPlaystatus *pPlaystatus, MNCallJava *pJava, const char *_url) {
    this->playstatus = pPlaystatus;
    this->callJava = pJava;
    this->url = _url;
    pthread_mutex_init(&seek_mutex, NULL);

    pthread_mutex_init(&init_mute, NULL);
}

void MNFFmpeg::parpared() {
    //之前是主线程，所以要创建子线程解码
    pthread_create(&decodeThread, NULL, decodeFFmpeg, this);
}


//子线程
void MNFFmpeg::decodeFFmpegThread() {

    LOGE("open url :%s", url);

    pthread_mutex_lock(&init_mute);

    av_register_all();
    avformat_network_init();
    pFormatCtx = avformat_alloc_context();

    if (avformat_open_input(&pFormatCtx, url, NULL, NULL) != 0) {
        if (LOG_DEBUG) {
            LOGE("can not open url :%s", url);
        }
        return;
    }

    if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
        if (LOG_DEBUG) {
            LOGE("can not find streams from %s", url);
        }
        return;
    }
    for (int i = 0; i < pFormatCtx->nb_streams; i++) {
        if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)//得到音频流
        {
            if (audio == NULL) {
                audio = new MNAudio(playstatus, pFormatCtx->streams[i]->codecpar->sample_rate,
                                    callJava);
                audio->streamIndex = i;
                audio->codecpar = pFormatCtx->streams[i]->codecpar;

                //pFormatCtx->duration单位是微妙，除以6个0才是秒
                audio->duration = pFormatCtx->duration / AV_TIME_BASE;
                audio->time_base = pFormatCtx->streams[i]->time_base;
            }
        }
    }

    AVCodec *dec = avcodec_find_decoder(audio->codecpar->codec_id);
    if (!dec) {
        if (LOG_DEBUG) {
            LOGE("can not find decoder");
        }
        return;
    }

    audio->avCodecContext = avcodec_alloc_context3(dec);
    if (!audio->avCodecContext) {
        if (LOG_DEBUG) {
            LOGE("can not alloc new decodecctx");
        }
        return;
    }

    if (avcodec_parameters_to_context(audio->avCodecContext, audio->codecpar) < 0) {
        if (LOG_DEBUG) {
            LOGE("can not fill decodecctx");
        }
        return;
    }

    if (avcodec_open2(audio->avCodecContext, dec, 0) != 0) {
        if (LOG_DEBUG) {
            LOGE("cant not open audio strames");
        }
        return;
    }
    callJava->onCallPrepared(CHILD_THREAD);

    pthread_mutex_unlock(&init_mute);
}


void MNFFmpeg::start() {
    if (audio == NULL) {
        if (LOG_DEBUG) {
            LOGE("audio is null");
            return;
        }
    }
    audio->play();

    int count = 0;
    while (playstatus != NULL && !playstatus->exit) {

        if (playstatus->seeking) {
            continue;
        }
        // audio->sample_rate/1024 约等于40？咋来的？
        if (audio->queue->getQueueSize() > audio->sample_rate / 1024) {
            continue;
        }

        AVPacket *avPacket = av_packet_alloc();

        //av_read_frame：0 if OK, < 0 on error or end of file. On error, pkt will be blank
        if (av_read_frame(pFormatCtx, avPacket) == 0) {
            if (avPacket->stream_index == audio->streamIndex) {
                //解码操作
                count++;
                if (LOG_DEBUG) {
                    LOG3("解码第 %d 帧", count);
                }
                audio->queue->putAvpacket(avPacket);
            } else {
                //不是音频数据就释放掉
                av_packet_free(&avPacket);
                av_free(avPacket);
            }
        } else {
            //读到文件末尾
            av_packet_free(&avPacket);
            av_free(avPacket);
            //但不代表不能播放,所以还要轮训，等消费者消费完
            while (playstatus != NULL && !playstatus->exit) {
                if (audio->queue->getQueueSize() > 0) {
                    continue;
                }
//                else if (audio->queue->getQueueSize() == 0) {
//                    //TODO
//                    continue;
//                }
                else {
                    playstatus->exit = true;
                    break;
                }
            }


        }
    }
    if (LOG_DEBUG) {
        LOGD("解码且播放完成");
    }
}

void MNFFmpeg::seek(int second) {
    if (audio != NULL && audio->duration > 0) {

        if (second > 0 && second < audio->duration) {
            playstatus->seeking = true;

            audio->queue->clearAvpacket();
            audio->clock_time = 0;
            audio->last_time = 0;

            pthread_mutex_lock(&seek_mutex);
            //-1 代表seek所有轨道，否则需要传入对应轨道
            int rel = second * AV_TIME_BASE;
            //耗时操作
            int ret = avformat_seek_file(pFormatCtx, -1, INT64_MIN, rel, INT64_MAX, 0);
//            if (ret>0){
//                audio->queue->clearAvpacket();
//                audio->clock_time = 0;
//                audio->last_time = 0;
//            }
            LOG2("avformat_seek_file :%d", ret);

            pthread_mutex_unlock(&seek_mutex);
            playstatus->seeking = false;

        }

    }
}

void MNFFmpeg::pause() {
    if (audio != NULL) {
        audio->pause();
    }
}

void MNFFmpeg::resume() {
    if (audio != NULL) {
        audio->resume();
    }
}

void MNFFmpeg::setMute(int i) {
    if (audio != NULL) {
        audio->setMute(i);
    }
}

void MNFFmpeg::setSpeed(float d) {
    if (audio != NULL) {
        audio->setSpeed(d);
    }
}

void MNFFmpeg::setPitch(float d) {
    if (audio != NULL) {
        audio->setPitch(d);
    }
}

void MNFFmpeg::release() {
    LOGE("开始释放");

    playstatus->exit = true;

    int sleepCount = 0;
    pthread_mutex_lock(&init_mute);
//    while (!exit) {
//        if (sleepCount > 1000) {
//            exit = true;
//        }
//        LOGE("wait ffmpeg  exit %d", sleepCount);
//        sleepCount++;
//        av_usleep(1000 * 10);//暂停10毫秒
//    }

    if (audio != NULL) {
        audio->release();
        delete (audio);
        audio = NULL;
    }

    LOGE("释放 封装格式上下文");
    if (pFormatCtx != NULL) {
        avformat_close_input(&pFormatCtx);
        avformat_free_context(pFormatCtx);
        pFormatCtx = NULL;
    }

    LOGE("释放 callJava");
    callJava = NULL;
    LOGE("释放 playstatus");
    playstatus = NULL;

    pthread_mutex_unlock(&init_mute);

}
